//
//  ViewController.m
//  ForTest
//
//  Created by ZJ on 2018/3/12.
//  Copyright © 2018年 iCatch Technology Inc. All rights reserved.
//

#import "ViewController.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import <Foundation/Foundation.h>
#import "TESTTowel.h"
#import "NSString+MD5.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
//    [self test];
//    NSLog(@"1");
//    dispatch_async(dispatch_get_global_queue(0, 0), ^{
//        NSLog(@"2");
//        [self performSelector:@selector(test) withObject:nil afterDelay:2];
//    });
//    NSLog(@"3");
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
//    TESTTowel *myTowel = [TESTTowel new];
//    [self addObserver:nil forKeyPath:@"location" options:NSKeyValueObservingOptionNew context:NULL];
    
//    [self runtimeTest];
//    NSArray *array = [[NSArray alloc] initWithObjects:@(1), @(2), @(3), @(4), @(3), nil];
//    NSMutableSet *mSet = [NSMutableSet setWithCapacity:3];
//    [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//        [mSet addObject:obj];
//    }];
//    
//    NSLog(@"mSet: %zd", mSet.count);
    
    NSLog(@"----- %@", [@"hello" md5Encrypt]);
    NSLog(@"----- %@", [@"hello" md5]);
}

- (void)test {
    NSLog(@"===================== hihi ====");
}

- (void)runtimeTest {
    // 创建一个字典数组，每个字典都会保存类的名称、层级以及给定类的方法列表
    NSMutableArray *runtimeClassInfo = [NSMutableArray array];
    
    // 保存注册类的数量
    unsigned int classCount = 0;
    
    // 创建一个指针指向应用当前加载的所有注册类的列表
    Class *classList = objc_copyClassList(&classCount);
    
    // 列表单中的每个类
    for (int i = 0; i < classCount; i++) {
        // 将类的列表作为一个C语言数组处理，获取其中的一个类
        Class currentClass = classList[i];
        
        // 将类的名称作为字符串处理
        NSString *className = NSStringFromClass(currentClass);
        
//        NSLog(@"--> %@", className);
        NSArray *hierarchy = [self hierarchyForClass:currentClass];
        NSArray *methods = [self methodsForClass:currentClass];
        NSDictionary *classInfoDict = @{@"className" : className,
                                        @"hierarchy" : hierarchy,
                                        @"methods"   : methods,
                                        };
        
        [runtimeClassInfo addObject:classInfoDict];
    }
    
    free(classList);
    
    NSSortDescriptor *alphaAsc = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
    NSArray *sortedArray = [runtimeClassInfo sortedArrayUsingDescriptors:@[alphaAsc]];
    
    NSLog(@"There are %ld classes registered with this program's Runtime.", sortedArray.count);
    NSLog(@"--> %@", sortedArray);
}

// 获取类的层级关系
- (NSArray *)hierarchyForClass:(Class)cls {
    NSMutableArray *classHierarchy = [NSMutableArray array];
    
    for (Class c = cls; c != nil; c = class_getSuperclass(c)) {
        NSString *className = NSStringFromClass(c);
        [classHierarchy insertObject:className atIndex:0];
    }
    
    return classHierarchy.copy;
}

// 获取类的方法
- (NSArray *)methodsForClass:(Class)cls {
    unsigned int methodCount = 0;
    
    // 创建一个指针指向给定类的所有方法列表
    Method *methodList = class_copyMethodList(cls, &methodCount);
    
    NSMutableArray *methodArray = [NSMutableArray array];
    
    // 列表中的每个方法
    for (int m = 0; m < methodCount; m++) {
        // 将方法列表作为一个C语言数组处理，获取其中的一个方法（获取当前方法）
        Method currentMethod = methodList[m];
        
        // 获取当前方法的选择器
        SEL methodSelector = method_getName(currentMethod);
        
        [methodArray addObject:NSStringFromSelector(methodSelector)];
    }
    
    return methodArray.copy;
}

- (void)messageSend {
    NSString *nameStr = @"qwert";
    objc_msgSend();
//    NSString *capsStr = objc_msgSend();
//    NSLog(@"old string: %@ --> new string: %@", nameStr, capsStr);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
